<?php

use Symfony\Component\DomCrawler\Crawler;

/**
 * Description of Indexer
 *
 * @author Guy
 */
class Indexer extends Crawler {

    /**
     *
     * @var string[] 
     */
    protected $mots_vides;

    /**
     *
     * @var IndexerInterface
     */
    protected $indexer;
    
    public static $IGNORE_NODES = array("script", "style", "link", "noscript");

    public function __construct(IndexerInterface $indexer) {
        parent::__construct();

        $this->indexer = $indexer;
        $this->mots_vides = array();
    }

    /**
     * Retourne les occurences d'un document
     * @param Document $document
     * @param IndexerInterface $indexer
     * @return Occurence[]
     */
    public function getOccurences(Document $document) {
        $crawler = new Crawler();
        $crawler->addContent($document->getContent());

        $occurences = $this->getOccurencesFromNodes(array(), $crawler->filter("body"));
        $finalOccurences = array();
        
        foreach($occurences as $occurence)
        {
            if($occurence instanceof Occurence)
            {
                $finalOccurences[] = $occurence->setDocument($document);
            }else
            {
                
            }
        }

        return $finalOccurences;
    }

    /**
     * Retourne les occurences rencontrées dans un document
     * @param array $accu
     * @param Indexer $nodes
     * @return Occurence[]
     */
    protected function getOccurencesFromNodes($accu, Crawler $nodes) {
        
        //Parcours des noeuds
        $nodes->each(function(Crawler $node) use(& $accu) {
            //Recherche de noeuds de type Text sur les enfants du noeud courant
            $currentAccu    = $this->searchOccurencesFromTextNode($node);

            //Parcours récursif des enfants (filtrés) du noeud
            $childAccu      = $this->getOccurencesFromNodes($accu, $node->children());

            $accu           = array_merge($currentAccu, $childAccu);
        });

        return $accu;
    }

    /**
     * Recherche les enfants de type Texte dans le noeud fourni et y extrait les occurences
     * @param Indexer $node
     * @return Occurences[]
     */
    protected function searchOccurencesFromTextNode(Crawler $node) {
        $occurences = array();
        foreach ($node as $nodeElement) {
            foreach ($nodeElement->childNodes as $domNode) {
                if ($domNode->nodeType === XML_TEXT_NODE) { //Noeud de type texte
                    $occurences = array_merge($occurences, $this->getOccurencesFromText($domNode->nodeValue, $node));
                }
            }
        }

        return $occurences;
    }

    protected function createOccurence(Crawler $node) {
        $occurence      = new Occurence;
        $parents        = $node->parents();
        $parent         = $parents->count() ? $parents->eq(0) : array();

        foreach ($parent as $parentElement) {
            $occurence->setBalise($parentElement->nodeName);
        }
        return $occurence;
    }

    protected function getOccurencesFromText($text, $node) {
        $terms          = $this->indexer->wordsToTerm($text);
        $occurences[]   = array();
        foreach ($terms as $term) {
            $occurence      = $this->createOccurence($node);
            $occurences[]   = $occurence->setMot($term["mot"])->setTerme($term["term"]);
        }

        return $occurences;
    }

    /**
     * Retourne les index calculés à partir des occurences trouvées dans un documennt
     * @param Occurence[] $occurences
     * @return array
     */
    public function getIndexes($occurences) {
        $indexes = array();

        //Calcul des poids pour chaque occurence
        foreach ($occurences as $occurence) {
            $document   = $occurence->getDocument();
            $key        = $document->getId();
            $subKey     = $occurence->getTerme();

            if (!isset($indexes[$key])) {
                $indexes[$key] = array();
            }

            if (!isset($indexes[$key][$subKey])) {
                $index = new Index();
                $indexes[$key][$subKey] = $index->setDocument($document)
                        ->setTerme($occurence->getTerme())
                        ->setPoids(0);
            }
            
            $newPoids = $indexes[$key][$subKey]->getPoids() + $this->indexer->getPoids($document, $occurence);
            $indexes[$key][$subKey]->setPoids($newPoids);
        }

        return $indexes;
    }
}
